package com.sz.biz.app.web.security;

import com.sz.common.base.logger.Logger;

import com.sz.common.base.web.shiro.cache.ShiroCacheFactory;
import com.sz.common.core.service.Principal;
import com.sz.common.core.service.PrincipalManager;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.DefaultSessionKey;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Function: 在线会话管理器 <br>
 * Author: Charles <br>
 * Date: 2017-01-23 09:39:00
 */
@Service("onlineSessionManager")
public class OnlineSessionManager {
    protected Logger logger = Logger.getLogger(this.getClass());

    @Autowired
    DefaultSessionManager sessionManager;

    @Autowired
    PrincipalManager principalManager;

    @Value("${logistics.session.cache.key}")
    private String onlineSessionCacheKey;

    protected Cache<String, Serializable> onlineSessionKeyCache;
    protected SessionListener sessionListener;


    @PostConstruct
    public void init() {
        onlineSessionKeyCache = ShiroCacheFactory.getInstance().getOnlineSessionKeyCache(onlineSessionCacheKey);
        sessionListener = createSessionListener();
        sessionManager.getSessionListeners().add(sessionListener);
    }

    protected SessionListener createSessionListener() {
        SessionListener sessionListener = new SessionListener() {
            @Override
            public void onStart(Session session) {
                logger.trace("Session start:" + session.getId());
                if (principalManager.isAnonymousSupported()) {
                    principalManager.createAnonymousPrincipal();
                }
            }

            @Override
            public void onStop(Session session) {
                logger.trace("Session stop:" + session.getId());
                Principal principal = getPrincipalFromSession(session);
                if (principal != null) {
                    String name = principal.getAccountName();
                    removeOnlineSession(name);
                }
            }

            @Override
            public void onExpiration(Session session) {
                logger.trace("Session expired:" + session.getId());
                Principal principal = getPrincipalFromSession(session);
                if (principal != null) {
                    String name = principal.getAccountName();
                    removeOnlineSession(name);
                }
            }
        };
        return sessionListener;
    }


    @PreDestroy
    public void destroy() {

    }

    public void addOnlineSession(String username, Serializable sessionId) {
        onlineSessionKeyCache.put(username, sessionId);
        //getOnlineSessions();
    }

    public void removeOnlineSession(String username) {
        onlineSessionKeyCache.remove(username);
    }

    public Serializable getSessionId(String username) {
        return onlineSessionKeyCache.get(username);
    }

    /**
     * 获取在线用户信息
     *
     * @return
     */
    public Map<String, Principal> getOnlineSessions() {
        Map<String, Principal> map = new HashMap<>();
        Set<String> keys = onlineSessionKeyCache.keys();
        for (String key : keys) {
            Serializable sessionId = onlineSessionKeyCache.get(key);
            Session session = sessionManager.getSession(new DefaultSessionKey(sessionId));
            Principal principal = getPrincipalFromSession(session);
            if (principal != null) {
                map.put(key, principal);
            }
        }
        return map;
    }

    /**
     * @return
     */
    public int getOnlineCount() {
        return this.onlineSessionKeyCache.size();
    }

    /**
     * knock out session
     *
     * @param userName
     */
    public void kickoutOnlineSession(String userName) {
        Serializable sessionId = getSessionId(userName);
        if (sessionId != null && sessionId.toString().length() > 0) {
            Session session = sessionManager.getSession(new DefaultSessionKey(sessionId));
            if (session != null) {
                session.stop();
            }
        }
    }


    public Principal getPrincipalFromSession(Session session) {
        return principalManager.getPrincipal(session);
    }
}
